<!--
 * Copyright © 2022
 * @Author: zhangxiang
 * @Date: 2022-08-03 17:02:33
 * @LastEditors: zhangxiang
 * @LastEditTime: 2023-09-21 14:22:38
 * @Description:
 *
-->
<template>
  <el-dialog
    class="upload-app-dialog"
    :title="title"
    :visible="show"
    width="900px"
    top="10vh"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    @close="closeClick"
  >
    <div v-if="isInPatchUploading" class="uploading">
      <el-progress
        style="width: 100%"
        :text-inside="true"
        :stroke-width="14"
        :percentage="uploadingInfo.progress"
      />
      <div class="info">
        <div class="name item">{{ uploadingInfo.name }}</div>
        <div class="text item">{{ uploadingInfo.text }}</div>
        <div class="data item">
          <div class="data-item size">{{ uploadingInfo.size }}</div>
          <div v-if="uploadingInfo.speed" class="data-item speed">
            {{ uploadingInfo.speed }}
          </div>
        </div>
      </div>
    </div>
    <el-form
      v-else
      ref="uploadForm"
      :rules="rules"
      :model="form"
      label-width="auto"
      size="medium"
    >
      <el-form-item v-if="!isEdit" class="upload-file" prop="fileName">
        <template v-if="!hasSelectFile">
          <el-button
            size="medium"
            type="primary"
            icon="el-icon-upload2"
            @click="uploadAppFile"
          >上传应用文件</el-button>
          <div class="upload-hint">
            <i class="el-icon-info icon"></i>
            <div class="text">
              点击上传应用文件Zip包，包含应用镜像，yaml文件及配置说明文件。您可以最多添加10个镜像压缩包。
            </div>
          </div>
        </template>
        <template v-else>
          <div class="selected-info">
            <span class="name">{{ form.fileName }}</span>
            <i class="el-icon-circle-close icon" @click="selectedCancel"></i>
          </div>
        </template>
      </el-form-item>
      <el-form-item class="item" label="应用名称" prop="applicationName">
        <el-input
          v-model="form.applicationName"
          :disabled="isEdit"
          placeholder="请输入应用名称"
        />
      </el-form-item>
      <el-form-item class="item category" label="应用分类" prop="category">
        <el-select
          v-model="form.category"
          placeholder="请选择应用分类"
          style="width: 47%"
        >
          <el-option
            v-for="item in categoryOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
        <el-select
          v-model="form.type"
          placeholder="请选择应用子分类"
          style="width: 47%; margin-left: 6%"
        >
          <el-option
            v-for="item in typeOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="应用标签" prop="label">
        <div class="label-item">
          <span class="text">对象及场景：</span>
          <div class="content">
            <div
              v-for="(item, index) in labelObjectScene"
              :key="index"
              :class="['label', item.select ? 'select' : '']"
              @click="lableClick(index, 'objectScene')"
            >
              {{ item.label }}
            </div>
          </div>
        </div>
        <div class="label-item">
          <span class="text">技术：</span>
          <div class="content">
            <div
              v-for="(item, index) in lableTechnology"
              :key="index"
              :class="['label', item.select ? 'select' : '']"
              @click="lableClick(index, 'technology')"
            >
              {{ item.label }}
            </div>
          </div>
        </div>
      </el-form-item>
      <el-form-item class="item" label="应用版本" prop="version">
        <el-input v-model="form.version" placeholder="请输入应用版本" />
      </el-form-item>
      <el-form-item label="部署资源池" prop="deployResourceInfo">
        <el-radio-group
          v-model="form.deployResourceInfo.cloudScope"
          @input="cloudScopeChange"
        >
          <el-radio :label="'public'">公有云平台</el-radio>
          <el-radio :label="'private'">私有云平台</el-radio>
        </el-radio-group>
        <div v-if="form.deployResourceInfo.cloudScope" class="resourceInfos">
          <el-checkbox
            v-model="cloudCheckAll"
            :indeterminate="cloudIndeterminate"
            @change="handleCloudCheckAllChange"
          >全选</el-checkbox>
          <el-checkbox-group
            v-model="form.deployResourceInfo.resourceInfos"
            @change="handleCloudResourceChange"
          >
            <el-checkbox
              v-for="item in currentCloudVendors"
              :key="item.value"
              :label="item.value"
            >{{ item.label }}</el-checkbox>
          </el-checkbox-group>
        </div>
      </el-form-item>
      <el-form-item label="应用描述" prop="description">
        <el-input
          v-model="form.description"
          maxlength="100"
          rows="3"
          type="textarea"
          show-word-limit
          placeholder="请输入应用及镜像描述"
        />
      </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button size="small" @click="cancelClick">取 消</el-button>
      <el-button
        type="primary"
        size="small"
        :loading="confirmLoading"
        @click="confirmClick"
      >确 定</el-button>
    </div>
    <FilePatchUploader
      ref="fileUploader"
      :accept="'application/zip'"
      :patch-size="10"
      @selected="fileSelectedCallback"
      @progress="fileUploadProgress"
      @success="fileUploadSuccess"
      @error="fileUploadError"
    />
  </el-dialog>
</template>

<script>
import {
  APP_CATEGORYS,
  APP_CATEGORY_TYPES_AI,
  APP_CATEGORY_TYPES_BIGDATA,
  APP_LABEL_OBJECTSCENE_AI,
  APP_LABEL_OBJECTSCENE_BIGDATA,
  APP_LABEL_TECHNOLOGY_AI,
  APP_LABEL_TECHNOLOGY_BIGDATA
} from '@/utils/cnap/constant'
import { isEmptyString } from '@/utils/index'
import FilePatchUploader from '@/components/FilePatchUploader'
import { updateApp } from '@/api/cnap/app-service'
import { mapGetters } from 'vuex'
import cloudVendorHandle from '@/views/mixin/cloudVendorHandle.js'

export default {
  name: 'UploadAppDialog',
  components: { FilePatchUploader },
  mixins: [cloudVendorHandle],
  props: {
    // 是否显示
    show: {
      type: Boolean,
      default: false
    },
    // 是否编辑
    isEdit: {
      type: Boolean,
      default: false
    },
    // 应用信息
    appInfo: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    /**
     * @description: 分类校验
     * @param {*} rule
     * @param {*} value
     * @param {*} callback
     * @return {*}
     */
    var validateCategory = (rule, value, callback) => {
      if (isEmptyString(this.form.category)) {
        callback(new Error('请选择应用分类'))
      } else if (isEmptyString(this.form.type)) {
        callback(new Error('请选择应用子分类'))
      } else {
        callback()
      }
    }
    /**
     * @description: 标签校验
     * @param {*} rule
     * @param {*} value
     * @param {*} callback
     * @return {*}
     */
    var validateLabel = (rule, value, callback) => {
      const objectSceneIllegal =
        !Array.isArray(value.objectScene) || value.objectScene.length <= 0
      const technologyIllegal =
        !Array.isArray(value.technology) || value.technology.length <= 0
      if (objectSceneIllegal || technologyIllegal) {
        callback(
          new Error(
            objectSceneIllegal
              ? '请至少选择一项对象及场景应用标签'
              : '请至少选择一项技术应用标签'
          )
        )
      } else {
        callback()
      }
    }
    /**
     * @description: 校验部署资源池
     * @param {*} rule
     * @param {*} value
     * @param {*} callback
     * @return {*}
     */
    var validateDeployResource = (rule, value, callback) => {
      if (isEmptyString(value.cloudScope)) {
        callback(new Error('请选择部署云平台'))
      } else if (value.resourceInfos.length === 0) {
        callback(new Error('请选择部署资源池'))
      } else {
        callback()
      }
    }
    return {
      categoryOptions: APP_CATEGORYS, // 分类选项
      typeOptions: [], // 类别选项
      title: '上传应用', // 标题
      // 校验规则
      rules: {
        // 文件名
        fileName: [
          {
            required: true,
            message: '请选择需要上传的应用文件',
            trigger: 'blur'
          }
        ],
        // 应用名
        applicationName: [
          { required: true, message: '请输入应用名称', trigger: 'blur' }
        ],
        // 类别
        category: [
          { required: true, validator: validateCategory, trigger: 'blur' }
        ],
        // 版本
        version: [
          { required: true, message: '请输入应用版本', trigger: 'blur' }
        ],
        deployResourceInfo: [
          // 部署资源池
          { required: true, message: '请选择部署资源池' },
          {
            required: true,
            validator: validateDeployResource,
            trigger: 'change'
          }
        ],
        // 描述
        description: [
          { required: true, message: '请输入应用及镜像描述', trigger: 'blur' }
        ],
        // 标签
        label: [{ required: true, validator: validateLabel, trigger: 'blur' }]
      },
      cloudCheckAll: false, // 全选
      cloudIndeterminate: false, // 云商选择不确定状态
      // 表单
      form: {
        applicationName: '', // 名称
        category: '', // 类别
        type: '', // 子分类
        label: {
          objectScene: [], // 对象及场景
          technology: [] // 技术
        },
        version: '', // 版本
        deployResourceInfo: {
          cloudScope: 'public',
          resourceInfos: []
        },
        description: '', // 描述
        fileName: '' // 文件名
      },
      confirmLoading: false,
      // 对象及场景标签
      labelObjectScene: APP_LABEL_OBJECTSCENE_AI.map((item) => {
        return {
          label: item,
          select: false
        }
      }),
      // 技术标签
      lableTechnology: APP_LABEL_TECHNOLOGY_AI.map((item) => {
        return {
          label: item,
          select: false
        }
      }),
      isInPatchUploading: false, // 是否正在分片上传中
      // 上传中信息
      uploadingInfo: {
        name: '', // 名称
        size: '', // 大小
        progress: 0, // 进度
        speed: '', // 速度
        text: '' // 提示文字
      }
    }
  },
  computed: {
    /**
     * @description: 用户名
     * @return {*}
     */
    ...mapGetters(['userName']),
    /**
     * @description: 是否已选择文件
     * @return {*}
     */
    hasSelectFile() {
      return !isEmptyString(this.form.fileName)
    },
    /**
     * @description: 公有云商
     * @return {*}
     */
    publicCloudVendors() {
      return this.cloudVendors.filter((item) => {
        return item.cloudScope === 'public'
      })
    },
    /**
     * @description: 私有云商
     * @return {*}
     */
    privateCloudVendors() {
      return this.cloudVendors.filter((item) => {
        return item.cloudScope === 'private'
      })
    },
    /**
     * @description: 当前云商资源池
     * @return {*}
     */
    currentCloudVendors() {
      return this.form.deployResourceInfo.cloudScope === 'public'
        ? this.publicCloudVendors
        : this.form.deployResourceInfo.cloudScope === 'private'
          ? this.privateCloudVendors
          : []
    }
  },
  watch: {
    /**
     * @description: 监听应用分类变化
     * @return {*}
     */
    'form.category': {
      handler(newVal) {
        if (newVal === 'AI') {
          // 修改应用子分类
          this.typeOptions = APP_CATEGORY_TYPES_AI
          this.form.type = ''
          // 修改应用标签
          // 应用标签-对象及场景
          this.labelObjectScene = APP_LABEL_OBJECTSCENE_AI.map((item) => {
            return {
              label: item,
              select: false
            }
          })
          this.form.label.objectScene = []
          // 修改应用标签
          // 应用标签-技术
          this.lableTechnology = APP_LABEL_TECHNOLOGY_AI.map((item) => {
            return {
              label: item,
              select: false
            }
          })
          this.form.label.technology = []
        } else if (newVal === 'BIGDATA') {
          // 修改应用子分类
          this.typeOptions = APP_CATEGORY_TYPES_BIGDATA
          this.form.type = ''
          // 修改应用标签
          // 应用标签-对象及场景
          this.labelObjectScene = APP_LABEL_OBJECTSCENE_BIGDATA.map((item) => {
            return {
              label: item,
              select: false
            }
          })
          this.form.label.objectScene = []
          // 修改应用标签
          // 应用标签-技术
          this.lableTechnology = APP_LABEL_TECHNOLOGY_BIGDATA.map((item) => {
            return {
              label: item,
              select: false
            }
          })
          this.form.label.technology = []
        }
      },
      immediate: true
    },
    /**
     * @description: 监听是否编辑
     * @return {*}
     */
    isEdit: {
      handler(newVal) {
        if (newVal) {
          // 初始化数据
          this.title = '编辑应用'
          this.form.applicationName = this.appInfo.name
          this.form.category = this.appInfo.category
          this.form.version = this.appInfo.version
          this.form.description = this.appInfo.description
          // 云资源池数据
          this.form.deployResourceInfo.cloudScope = this.appInfo
            .deployResourceInfo
            ? this.appInfo.deployResourceInfo.cloudScope || ''
            : ''
          this.form.deployResourceInfo.resourceInfos =
            this.appInfo.deployResourceInfo &&
            Array.isArray(this.appInfo.deployResourceInfo.resourceInfos)
              ? this.appInfo.deployResourceInfo.resourceInfos.map((item) => {
                return this.formatVendorAccount(
                  item.cloudVendor,
                  item.accountName
                )
              })
              : []
          this.$nextTick(() => {
            // 以下数据依赖于category的变化
            // 所以在下一个周期更新
            this.form.type = this.appInfo.type
            this.form.label = Object.keys(this.appInfo.label).includes(
              'objectScene'
            )
              ? JSON.parse(JSON.stringify(this.appInfo.label))
              : {
                objectScene: [],
                technology: []
              }
            // 更新应用标签-对象及场景
            this.labelObjectScene.forEach((element) => {
              if (this.form.label.objectScene.includes(element.label)) {
                element.select = true
              }
            })
            // 更新应用标签-技术
            this.lableTechnology.forEach((element) => {
              if (this.form.label.technology.includes(element.label)) {
                element.select = true
              }
            })
          })
        }
      },
      immediate: true
    }
  },
  mounted() {},
  methods: {
    /**
     * @description: 云资源选择切换
     * @param {*} val
     * @return {*}
     */
    handleCloudResourceChange(val) {
      this.cloudCheckAll = val.length === this.currentCloudVendors.length
      this.cloudIndeterminate =
        val.length > 0 && val.length < this.currentCloudVendors.length
    },
    /**
     * @description: 云资源全选点击
     * @param {*} val
     * @return {*}
     */
    handleCloudCheckAllChange(val) {
      this.form.deployResourceInfo.resourceInfos = val
        ? this.currentCloudVendors.map((item) => {
          return item.value
        })
        : []
      this.cloudIndeterminate = false
    },
    /**
     * @description: 云平台切换
     * @return {*}
     */
    cloudScopeChange() {
      this.form.deployResourceInfo.resourceInfos = []
      this.cloudCheckAll = false
      this.cloudIndeterminate = false
    },
    /**
     * @description: 标签点击
     * @param {*} index
     * @param {*} type
     * @return {*}
     */
    lableClick(index, type) {
      if (type === 'objectScene') {
        // 对象及场景
        const select = this.labelObjectScene[index].select
        this.labelObjectScene[index].select = !select
        const objectScene = []
        this.labelObjectScene.forEach((element) => {
          if (element.select) {
            objectScene.push(element.label)
          }
        })
        this.form.label.objectScene = objectScene // 保持最新的已选择
      } else if (type === 'technology') {
        // 技术
        const select = this.lableTechnology[index].select
        this.lableTechnology[index].select = !select
        const technology = []
        this.lableTechnology.forEach((element) => {
          if (element.select) {
            technology.push(element.label)
          }
        })
        this.form.label.technology = technology // 保持最新的已选择
      }
    },
    /**
     * @description: 文件上传失败
     * @param {*} err
     * @return {*}
     */
    fileUploadError(err) {
      console.log(err)
      this.isInPatchUploading = false
    },
    /**
     * @description: 文件上传成功
     * @return {*}
     */
    fileUploadSuccess() {
      this.closeClick()
      this.$emit('upload-success') // 抛出事件
    },
    /**
     * @description: 文件上传进度回调
     * @param {*} progress
     * @return {*}
     */
    fileUploadProgress(val) {
      this.uploadingInfo = val
    },
    /**
     * @description: 上传按钮点击
     * @return {*}
     */
    uploadAppFile() {
      this.$refs.fileUploader.triggerSelect() // 触发选择文件
    },
    // 取消已选择的文件
    selectedCancel() {
      this.$refs.fileUploader.cancelSelect() // 取消
      this.form.fileName = ''
    },
    /**
     * @description: 选择文件回调
     * @param {*} val
     * @return {*}
     */
    fileSelectedCallback(val) {
      this.form.fileName = val.name
    },
    /**
     * @description: 关闭
     * @return {*}
     */
    closeClick() {
      this.$refs.fileUploader.stopUploadFile() // 停止上传
      this.$emit('update:show', false)
    },
    /**
     * @description: 取消
     * @return {*}
     */
    cancelClick() {
      this.closeClick()
      this.$emit('cancel')
    },
    /**
     * @description: 确定
     * @return {*}
     */
    confirmClick() {
      // 表单校验
      this.$refs.uploadForm.validate((valid, obj) => {
        if (valid) {
          // 格式化云资源池
          const deployResourceInfo = Object.assign(
            {},
            this.form.deployResourceInfo
          )
          deployResourceInfo.resourceInfos =
            deployResourceInfo.resourceInfos.map((item) => {
              return this.splitCloudVendorParams(item)
            })
          if (this.isEdit) {
            // 编辑场景
            this.confirmLoading = true
            // 更新应用信息
            updateApp({
              id: this.appInfo.id,
              category: this.form.category,
              type: this.form.type,
              version: this.form.version,
              label: this.form.label,
              deployResourceInfo: deployResourceInfo,
              description: this.form.description
            })
              .then((res) => {
                this.$emit('update:show', false)
                this.$emit('edit-success') // 编辑成功回调
              })
              .finally(() => {
                this.confirmLoading = false
              })
          } else {
            // 上传场景
            // 额外传递数据
            const extraData = {
              applicationName: this.form.applicationName,
              category: this.form.category,
              type: this.form.type,
              version: this.form.version,
              description: this.form.description,
              userName: this.userName,
              deployResourceInfo: deployResourceInfo,
              label: this.form.label
            }
            // 开始上传
            this.$refs.fileUploader.startUploadFile(extraData)
            // 状态更新
            this.isInPatchUploading = true
          }
        }
      })
    }
  }
}
</script>

<style lang="less" scoped>
@import "@/assets/css/common.less";
.upload-app-dialog {
  .upload-file {
    /deep/ .el-form-item__content {
      margin-left: 0 !important;
    }
  }
  .upload-hint {
    margin-left: 20px;
    display: inline-flex;
    .icon {
      color: #b9b9b9;
      font-size: 17px;
      margin-right: 6px;
    }
    .text {
      .textStyle(14px , 400, #C3C3C3);
      line-height: 21px;
    }
  }
  .selected-info {
    display: flex;
    align-items: center;

    .name {
      .textStyle(14px , 500, #4a4a4a);
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .icon {
      font-size: 20px;
      margin-left: 10px;
      cursor: pointer;
    }
  }
  .item {
    display: inline-block;
    width: calc(50% - 12.5px);
    &.category {
      margin-left: 25px;
    }
  }
  .label-item {
    display: flex;
    margin-top: 10px;
    .text {
      width: 84px;
      .textStyle(14px , 500, #696969);
      line-height: 20px;
      flex-shrink: 0;
      text-align: right;
    }
    .content {
      display: flex;
      flex-wrap: wrap;
      .label {
        cursor: pointer;
        margin-left: 10px;
        margin-bottom: 10px;
        box-sizing: border-box;
        .textStyle(12px , 400, #696969);
        line-height: 18px;
        background: #f3f3f3;
        border-radius: 2px;
        border: 1px solid #c4c6cc;
        padding: 3px 8px;
        &.select {
          background: #d9ebff;
          border-radius: 2px;
          border-color: #0091ff;
          color: #0091ff;
        }
      }
    }
  }
  .resourceInfos {
    /deep/ .el-checkbox {
      line-height: 25px;
    }
    /deep/ .el-checkbox-group {
      line-height: 30px;
    }
  }
  .uploading {
    margin: 100px 0;

    .info {
      margin-top: 10px;
      display: flex;
      align-items: center;
      font-size: 14px;
      justify-content: space-between;

      .item {
        flex: 1;
      }
      .text {
        text-align: center;
      }

      .data {
        display: flex;
        align-items: center;
        justify-content: flex-end;
        .data-item {
          flex-shrink: 0;
          &.speed {
            margin-left: 20px;
          }
        }
      }
    }
  }
}
</style>
